#!/usr/bin/env python
# -*- coding: utf-8 -*-
# @Time    : 2023/2/19 4:28
# @Author : 闫峰
# @File    : rabbitmq_utils.py
import time

import pika
import threading
import json

class RabbitMq_:

    def __init__(self, exchange_name, queue_name, routing_key, mode='direct'):
        self.lock = threading.Lock()
        self.mode = mode
        self.queue_name = queue_name
        credentials = pika.PlainCredentials("admin", "Zhcx?2021")
        self.connection = pika.BlockingConnection(pika.ConnectionParameters(
            host='10.158.158.31', port=5672, credentials=credentials))
        self.channel = self.connection.channel()

        if self.mode == 'broadcast':
            # 发布/订阅模式：创建fanout交换机
            self.channel.exchange_declare(exchange=exchange_name, exchange_type='fanout')
            # 创建临时队列并绑定到交换机
            self.queue_name = self.channel.queue_declare(queue='', exclusive=True).method.queue
            self.channel.queue_bind(exchange=exchange_name, queue=self.queue_name, routing_key=routing_key)
        else:
            # 点对点模式：创建持久化队列
            self.channel.queue_declare(queue=self.queue_name, durable=True)

        self.exchange_name = exchange_name
        self.routing_key = routing_key

    def send_message(self, message, mode=None):
        with self.lock:
            mode = mode or self.mode
            if mode == 'broadcast':
                # 发布/订阅模式：将消息发送到交换机
                self.channel.basic_publish(exchange=self.exchange_name,
                                            routing_key='',
                                            body=json.dumps(message),
                                            properties=pika.BasicProperties(
                                                delivery_mode=2
                                            ))
            else:
                # 点对点模式：将消息发送到队列
                self.channel.basic_publish(exchange='',
                                            routing_key=self.routing_key,
                                            body=json.dumps(message),
                                            properties=pika.BasicProperties(
                                                delivery_mode=2
                                            ))

    def receive_message(self, func):
        with self.lock:
            def callback(ch, method, properties, body):
                body = json.loads(body)

                is_callback = func(body)
                # is_callback = func(*body)
                # print(f"获取到body={body}")

                if is_callback:
                    ch.basic_ack(delivery_tag=method.delivery_tag)
                    print(f"消息确认成功body={body}")
                    # print(f"消息确认成功")
                else:
                    ch.basic_nack(delivery_tag=method.delivery_tag, requeue=True)
                    print(f"消息确认失败body={body}")

            self.channel.basic_qos(prefetch_count=1)
            self.channel.basic_consume(queue=self.queue_name, on_message_callback=callback)
            print(' [*] Waiting for messages. To exit press CTRL+C')
            self.channel.start_consuming()

    def receive_message_by_multiparameter(self, func):
        with self.lock:
            def callback(ch, method, properties, body):
                body = json.loads(body)
                is_callback = func(*body)
                # is_callback = func(*body)
                # print(f"获取到body={body}")

                if is_callback:
                    ch.basic_ack(delivery_tag=method.delivery_tag)
                    # print(f"消息确认成功body={body}")
                    # print(f"消息确认成功")
                else:
                    ch.basic_nack(delivery_tag=method.delivery_tag, requeue=True)
                    print(f"消息确认失败body={body}")

            self.channel.basic_qos(prefetch_count=1)
            self.channel.basic_consume(queue=self.queue_name, on_message_callback=callback)
            print(' [*] Waiting for messages. To exit press CTRL+C')
            self.channel.start_consuming()

    def closeConnection(self):
        with self.lock:
            self.connection.close()

#
# if __name__ == '__main__':
#     """
#     步骤 1: 创建多个消费者实例
#     为每个消费者创建一个 RabbitMq_ 类的实例。每个实例都应该有自己的队列，但所有队列都绑定到同一个交换机。
#     """
#     rabbitmq_consumer1 = RabbitMq_('my_fanout_exchange', 'queue_consumer1', '', mode='broadcast')
#
#     # 创建第二个消费者实例
#     rabbitmq_consumer2 = RabbitMq_('my_fanout_exchange', 'queue_consumer2', '', mode='broadcast')
#
#     # ...可以继续创建更多消费者实例
#
#
#     """
#     # 步骤 2: 定义消息处理函数
#     # 为每个消费者实例定义一个消息处理函数，这个函数将在接收到消息时被调用。
#     """
#     def process_message_consumer1(message):
#         print(f"Consumer 1 received message: {message}")
#
#
#     def process_message_consumer2(message):
#         print(f"Consumer 2 received message: {message}")
#
#     """
#     步骤 3: 启动消息接收
#     使用 receive_message 方法启动每个消费者的消息接收。这个方法会阻塞，因为它会启动一个持续监听消息的循环。
#     """
#     # 启动消费者1接收消息
#     rabbitmq_consumer1.receive_message(process_message_consumer1)
#
#     # 启动消费者2接收消息
#     rabbitmq_consumer2.receive_message(process_message_consumer2)
#
#     # 注意：在实际应用中，你可能需要在不同的线程或进程中启动这些消费者，
#     # 以避免阻塞主程序的执行。
#
#
#     """
#     步骤 4: 发送消息
#     使用 send_message 方法发送消息到交换机。交换机会将消息广播到所有绑定的队列，因此所有消费者都将接收到这条消息。
#     """
#     # 创建一个发送者实例
#     # rabbitmq_sender = RabbitMq_('my_fanout_exchange', 'any_queue', '', mode='broadcast')
#     #
#     # # 发送消息
#     # message = {"yanfeng":"suhong"}
#     # for i in range(100):
#     #     rabbitmq_sender.send_message(message)
#     #
#     # # 完成后关闭发送者连接
#     # rabbitmq_sender.closeConnection()
#
#
#
#     """
#     注意事项
#     每个消费者都应该有自己的队列，但所有队列都绑定到同一个 fanout 类型的交换机。
#     消息处理函数应该根据每个消费者的需求进行实现。
#     receive_message 方法会阻塞调用它的线程，因此如果需要的话，你应该在单独的线程中启动消费者。
#     在实际部署中，你可能需要考虑线程安全、错误处理、消息确认等因素。
#     通过这种方式，你可以轻松地扩展消费者的数量，以满足你的应用程序的需求。每个消费者都将独立地接收和处理消息，从而提高应用程序的可扩展性和容错性
#     """


if __name__ == '__main__':
    # 创建第一个消费者实例
    consumer1 = RabbitMq_('my_fanout_exchange', 'queue_consumer1', '', mode='broadcast')

    # 创建第二个消费者实例
    # consumer2 = RabbitMq_('my_fanout_exchange', 'queue_consumer2', '', mode='broadcast')

    # 如需更多消费者，继续创建实例...
    def callback_consumer1(body):
        message = json.loads(body.decode())
        print(f"Consumer1 received message: {message}")
        return True

    consumer1.receive_message(callback_consumer1)